
/*
    Software License

    Copyright (C) 2021-05-24  Xoronos

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, version 3.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

/*
    Liabilities

    The software is provided "AS IS" without any warranty of any kind, either expressed,
    implied, or statutory, including, but not limited to, any warranty that the software
    will conform to specifications, any implied warranties of merchantability, fitness
    for a particular purpose, and freedom from infringement, and any warranty that the
    documentation will conform to the software, or any warranty that the software will
    be error free.

    In no event shall Xoronos be liable for any damages, including, but not limited to,
    direct, indirect, special or consequential damages, arising out of, resulting from,
    or in any way connected with this software, whether or not based upon warranty,
    contract, tort, or otherwise, whether or not injury was sustained by persons or
    property or otherwise, and whether or not loss was sustained from, or arose out of
    the results of, or use of, the software or services provided hereunder.

    To request the provided software under a different license you can contact us at
    support@xoronos.com
*/

#ifndef XORON_CRYPTO_UTIL_H
#define XORON_CRYPTO_UTIL_H

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

#include "xrn_crypto.h"
#include "xrn_settings.h"
#include "xrn_common.h"

#include "xrn_core.h"
#include "xrn_arithmetic.h"
#include "xrn_arithmetic_backend.h"

typedef struct block_load_variables_t {
    XBIT_TYPE extra_block_needed;
} block_load_variables_t;

typedef struct hash_load_variables_t {
    XBIT_TYPE extra_block_needed;
    XBIT_TYPE last_block;
} hash_load_variables_t;

typedef struct load_variables_t {
    uint64_t crc;
    uint64_t crc64;
    uint32_t crc32;
    uint16_t crc16;
    uint8_t crc8;
    uint8_t written_crc_bytes;
    XBIT_TYPE extra_block_needed;
    XBIT_TYPE last_block;
} load_variables_t;

typedef struct xstate_t {
    xnum_t *xnums;
} xstate_t;

int shuffle_binomial_keys( xring_signature_t * sig_shuffled
 );

int xrn_check_sparsity( xnum_t num
 );

int non_linear_start_check( xnum_t num, xrn_matrix_t * xm
 );

int loop_join_bytes( uint8_t * in_bytes_challenge,
                     uint64_t in_length_challenge,
                     uint64_t in_index_challenge,
                     uint8_t * in_bytes_solution,
                     uint64_t in_length_solution,
                     uint64_t in_index_solution,
                     uint8_t * out_bytes,
                     uint64_t out_length,
                     uint64_t * num_decoded_bytes,
                     xrn_encoding_param_t enc_param_challenge, xrn_crypto_extra_settings_t settings
 );

int loop_split_bytes( uint8_t * in_bytes,
                      uint64_t in_length,
                      uint8_t * out_bytes_challenge,
                      uint64_t out_length_challenge,
                      uint64_t * num_encoded_bytes_challenge,
                      uint8_t * out_bytes_solution,
                      uint64_t out_length_solution,
                      uint64_t * num_encoded_bytes_solution,
                      xrn_encoding_param_t enc_param_challenge, xrn_crypto_extra_settings_t settings
 );

int loop_join_stream( FILE * input_file_challenge_fpr,
                      FILE * input_file_solution_fpr,
                      FILE * output_file_join_fpw,
                      xrn_encoding_param_t enc_param_challenge, xrn_crypto_extra_settings_t settings
 );

int loop_split_stream( FILE * input_file_fpr,
                       FILE * output_file_challenge_fpw,
                       FILE * output_file_solution_fpw,
                       xrn_encoding_param_t enc_param_challenge, xrn_crypto_extra_settings_t settings
 );

int loop_dec_bytes( uint8_t * in_bytes,
                    uint64_t in_length,
                    uint8_t * out_bytes,
                    uint64_t out_length,
                    uint64_t in_index,
                    uint64_t * num_decoded_bytes,
                    xstate_t * hidden_state,
                    xrn_matrix_t * xm, xnum_t init_vector, xrn_encoding_param_t enc_param,
                    xrn_crypto_extra_settings_t settings
 );

int loop_enc_bytes( uint8_t * in_bytes,
                    uint64_t in_length,
                    uint8_t * out_bytes,
                    uint64_t out_length,
                    uint64_t out_index,
                    uint64_t * num_encoded_bytes,
                    xstate_t * hidden_state,
                    xrn_matrix_t * xm, xnum_t init_vector, xrn_encoding_param_t enc_param,
                    xrn_crypto_extra_settings_t settings
 );

int loop_enc_stream( FILE * fpi,
                     FILE * fpo,
                     xstate_t * hidden_state,
                     xrn_matrix_t * xm, xnum_t init_vector, xrn_encoding_param_t enc_param,
                     xrn_crypto_extra_settings_t settings
 );

int loop_dec_stream( FILE * fpi,
                     FILE * fpo,
                     xstate_t * hidden_state,
                     xrn_matrix_t * xm, xnum_t init_vector, xrn_encoding_param_t enc_param,
                     xrn_crypto_extra_settings_t settings
 );

int add_padding_block( xstate_t * block_variable, uint8_t padding_type, uint64_t start, uint64_t stop
 );

int add_padding_stream( xstate_t * block_variable, uint8_t padding_type, uint64_t start, uint64_t stop
 );

int padding_start_index( xstate_t * block_variable, xrn_crypto_extra_settings_t settings
 );

void print_block_cipher( xstate_t bv, XBIT_TYPE padding_present
 );

void print_cipher( xstate_t bv, XBIT_TYPE padding_present
 );

int xrn_encrypt_symmetric_internal( xrn_matrix_t * xm,
                                    xstate_t * bv,
                                    uint64_t block_index,
                                    xstate_t * hidden_state,
                                    xnum_t input_vector, xstate_t * output_block,
                                    xrn_crypto_extra_settings_t settings
 );

void xrn_compress_state( xstate_t state, xnum_t * o, xrn_crypto_extra_settings_t settings
 );

int xrn_round_state( xstate_t * state_i,
                     xrn_matrix_t * xm,
                     xstate_t * hidden_state, xstate_t * state_o, xrn_crypto_extra_settings_t settings
 );

void crypto_block_init( block_load_variables_t * load_variables, xrn_crypto_extra_settings_t settings
 );

void crypto_hash_init( hash_load_variables_t * load_variables
 );

void crypto_init( load_variables_t * load_variables, uint8_t crc_bytes
 );

int plain_text_2_hash_block( FILE * fpi,
                             int index,
                             xstate_t * block_variable,
                             hash_load_variables_t * load_variables, xrn_crypto_extra_settings_t settings
 );

int from_bytes_2_hash_block( uint8_t * str,
                             int index,
                             int len,
                             xstate_t * block_variable,
                             hash_load_variables_t * load_variables, xrn_crypto_extra_settings_t settings
 );
int plain_text_2_cipher( FILE * fpi,
                         int index,
                         xstate_t * block_variable,
                         load_variables_t * load_variables, xrn_crypto_extra_settings_t settings
 );

int bytes_2_cipher( uint8_t * bytes,
                    int length,
                    int index,
                    xstate_t * bv, load_variables_t * load_variables, xrn_crypto_extra_settings_t settings
 );

int init_round_state( xrn_matrix_t * xm,
                      xnum_t init, uint64_t block_id, xstate_t * state, xrn_crypto_extra_settings_t settings
 );

int expand_xnum( xrn_matrix_t * xm, xnum_t iv, xstate_t * state_o, xrn_crypto_extra_settings_t settings
 );

int dump_two_xnums( xnum_t num1,
                    xnum_t num2,
                    xrn_lib_xtype_t type, uint8_t crc_bytes, FILE * fp, xrn_crypto_extra_settings_t settings
 );

int load_two_xnums( xnum_t * xnum1,
                    xnum_t * xnum2,
                    uint8_t * crc_bytes,
                    uint8_t * state_size,
                    xrn_lib_xtype_t * type, xrn_lib_xtype_t exp_type, FILE * fp,
                    xrn_crypto_extra_settings_t settings
 );

int xrn_mix( xstate_t * state_i,
             xrn_matrix_t * xm,
             xstate_t * hidden_state, xstate_t * state_o, xrn_crypto_extra_settings_t settings
 );

int xrn_cross_traverses( xstate_t * state_i, xrn_matrix_t * xm, xstate_t * state_o,
                         xrn_crypto_extra_settings_t settings
 );

int check_crypto_extra_settings_value( xrn_crypto_extra_settings_t settings
 );

void print_block_variable( xstate_t * block_variable, int size
 );

void print_state_xnums( xstate_t state, int state_size
 );

void print_extra_settings_t( xrn_crypto_extra_settings_t settings
 );

void initialize_xstate_t( xstate_t * state, uint8_t size
 );

void print_xblock_settings_t( xblock_settings_t block
 );

#endif
